package com.mx.adapt.picker

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.view.ViewTreeObserver
import android.view.animation.DecelerateInterpolator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import androidx.recyclerview.widget.RecyclerView
import com.mx.adapt.MXBaseSimpleAdapt
import com.mx.adapt.utils.MXUtils

open class MXScrollPickerView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : RecyclerView(context, attrs) {
    private val manager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
    private val pickerAdapt = MXScrollPickerAdapt(this)

    private var itemSize = 5 // 当前显示几条数据
    internal val itemOffset: Int
        get() = (itemSize - 1) / 2
    internal val itemHeight get() = (getAllHeight() / itemSize)

    private var itemSelect: IMXSelect? = null
    private var currentSelectIndex = NO_POSITION

    // 滚动动画时长
    private var animationDuration: Int = 500
    private var itemCount = pickerAdapt.itemCount

    // 中间选中的阴影
    private var dashColor: Int? = Color.parseColor("#33999999")
    private val dashPaint = Paint().apply { style = Paint.Style.FILL }
    private val dashRectF = RectF()

    init {
        LinearSnapHelper().attachToRecyclerView(this)
        super.setLayoutManager(manager)
        super.setAdapter(pickerAdapt)
        pickerAdapt.setItemClick { position, _ ->
            val size = pickerAdapt.itemCount
            if (position < itemOffset) return@setItemClick
            if (position >= size - itemOffset) return@setItemClick
            smoothScrollTo(position - itemOffset, true)
        }

        viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
            override fun onPreDraw(): Boolean {
                // MXUtils.log("onPreDraw width=$width,height=$height")
                pickerAdapt.notifyDataSetChanged()
                viewTreeObserver.removeOnPreDrawListener(this)
                return true
            }
        })
    }

    private val scrollListener = object : OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            if (newState == SCROLL_STATE_IDLE) {
                notifySelectChange(manager.findFirstCompletelyVisibleItemPosition())
            }
        }
    }

    override fun setLayoutManager(layout: LayoutManager?) {
        throw Exception("Forbidden call func 'setLayoutManager()'")
    }

    override fun setAdapter(adapter: Adapter<*>?) {
        throw Exception("Forbidden call func 'setAdapter()'")
    }

    override fun addItemDecoration(decor: ItemDecoration) {
    }

    override fun addItemDecoration(decor: ItemDecoration, index: Int) {
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        dashColor?.let { dash ->
            val itemHeight = itemHeight
            val itemOffset = itemOffset
            dashPaint.color = dash
            dashRectF.left = 0f
            dashRectF.right = width.toFloat()
            dashRectF.top = itemHeight * itemOffset.toFloat()
            dashRectF.bottom = itemHeight * (itemOffset + 1).toFloat()
            canvas.drawRect(dashRectF, dashPaint)
        }
    }

    private fun getAllHeight() = height - paddingTop - paddingBottom

    /**
     * 设置中间色带颜色
     */
    fun setDashColor(color: Int?) {
        dashColor = color
        postInvalidate()
    }

    /**
     * 设置滚动动画时长
     * 设置为0时，跳过动画
     */
    fun setAnimationDuration(durationMs: Int) {
        animationDuration = durationMs
    }

    /**
     * 设置显示个数，需要是基数且不小于3
     */
    fun setItemSize(size: Int) {
        if (size % 2 == 0) {
            throw Exception("数量不能为双数！")
        }
        if (size < 3) {
            throw Exception("最小显示行数为3")
        }
        itemSize = size
        postInvalidate()
        pickerAdapt.notifyDataSetChanged()
    }

    open fun setMXAdapt(adapt: MXBaseSimpleAdapt<*>?) {
        pickerAdapt.adapt?.unregisterAdapterDataObserver(adaptObserver)
        pickerAdapt.adapt = adapt
        adapt?.registerAdapterDataObserver(adaptObserver)
        pickerAdapt.notifyDataSetChanged()

        removeOnScrollListener(scrollListener)
        addOnScrollListener(scrollListener)
    }

    /**
     * 滚动到对应位置
     * @param index 位置
     * @param animation 是否滚动动画
     */
    fun setSelectIndex(index: Int, animation: Boolean = false) {
        val size = pickerAdapt.adapt?.itemCount ?: 0
        val targetIndex = when {
            (size < 0) -> 0
            (index >= size) -> size - 1
            (index < 0) -> 0
            else -> index
        }
        // MXUtils.log("setSelectIndex")
        smoothScrollTo(targetIndex, animation)
        post {
            smoothScrollTo(targetIndex, animation)
        }
    }

    /**
     * 获取当前位置
     */
    fun currentSelectIndex(): Int {
        return currentSelectIndex
    }

    /**
     * 监听滚动变化
     */
    fun setOnSelectListener(listener: IMXSelect?) {
        itemSelect = listener
        notifySelectChange(manager.findFirstCompletelyVisibleItemPosition())
    }

    private val adaptObserver = TypeObserver()

    private inner class TypeObserver : AdapterDataObserver() {
        override fun onChanged() {
            pickerAdapt.notifyDataSetChanged()
            checkSelectIndexOutRange()
        }

        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            pickerAdapt.notifyItemRangeInserted(positionStart + itemOffset, itemCount)
            checkSelectIndexOutRange()
        }

        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
            pickerAdapt.notifyItemRangeRemoved(positionStart + itemOffset, itemCount)
            checkSelectIndexOutRange()
        }

        override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
            pickerAdapt.notifyItemRangeChanged(positionStart + itemOffset, itemCount)
            checkSelectIndexOutRange()
        }

        override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
            pickerAdapt.notifyItemRangeChanged(positionStart + itemOffset, itemCount, payload)
            checkSelectIndexOutRange()
        }

        override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
            pickerAdapt.notifyItemMoved(fromPosition + itemOffset, toPosition + itemOffset)
            checkSelectIndexOutRange()
        }

        private fun checkSelectIndexOutRange() {
            if (itemCount != pickerAdapt.itemCount) {// 监听数量的变化，变化后需要校验当前选中位置
                itemCount = pickerAdapt.itemCount
                MXUtils.log("checkSelectIndexOutRange($itemCount)")
                post { notifySelectChange(manager.findFirstCompletelyVisibleItemPosition()) }
            }
        }
    }

    private fun notifySelectChange(index: Int) {
        if (index < 0 && index != NO_POSITION) return
        if (index == currentSelectIndex) return
        currentSelectIndex = index
        MXUtils.log("notifySelectChange($index)")
        itemSelect?.onSelect(index)
    }

    private fun smoothScrollTo(position: Int, animation: Boolean) {
        notifySelectChange(position)
        if (animation && itemHeight > 0 && animationDuration > 0) {
            val current = manager.findFirstCompletelyVisibleItemPosition()
            val top = (manager.findViewByPosition(current)?.top ?: 0)
            val dy = (itemHeight * (position - current)) + top
            smoothScrollBy(0, dy, DecelerateInterpolator(), animationDuration)
        } else {
            manager.scrollToPositionWithOffset(position, 0)
        }
    }
}